package com.qianheng.kit.web.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.lang.Nullable;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;

import java.io.UnsupportedEncodingException;
import java.util.Set;

@Slf4j
public class WebUtil {
    private static final Set<String> JSON_TYPES = Set.of(
        "application/json",
        "application/hal+json",
        "application/problem+json"
    );

    /**
     * 由于有cn.sixmac.infra.web.filter.TraceOncePerRequestFilter拦截，请求应该是缓存过的，此时可以重复读取。否者不能重复消费流。
     */
    public static ContentCachingRequestWrapper getHttpRequestWrapper() {
        ServletRequestAttributes requestAttributes =
            (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        if (requestAttributes == null) {
            log.error("WebUtil 无法获取请求属性");
            return null;
        }
        if (!(requestAttributes.getRequest() instanceof ContentCachingRequestWrapper)) {
            log.error("WebUtil HttpServletRequest未包装，不能重复获取，请检查是否配置TraceOncePerRequestFilter");
            return null;
        }
        ContentCachingRequestWrapper wrapper = (ContentCachingRequestWrapper)requestAttributes.getRequest();
        return wrapper;
    }

    /**
     * 由于有cn.sixmac.infra.web.filter.TraceOncePerRequestFilter拦截，请求应该是缓存过的，此时可以重复读取。否者不能重复消费流。
     *
     */
    public static @Nullable String getHttpRequestJsonBody() {
        ContentCachingRequestWrapper wrapper = getHttpRequestWrapper();
        if (wrapper == null)
            return null;

        String contentType = wrapper.getContentType();
        if (JSON_TYPES.contains(contentType)) {
            try {
                return new String(wrapper.getContentAsByteArray(), wrapper.getCharacterEncoding());
            } catch (UnsupportedEncodingException e) {
                log.error("WebUtil HttpServletRequest body流解析失败，返回null", e);
                return null;
            }
        } else {
            log.error("WebUtil HttpServletRequest 格式不支持解析 {}", contentType);
            return null;
        }

    }

    /**
     * 由于有cn.sixmac.infra.web.filter.TraceOncePerRequestFilter拦截，请求应该是缓存过的，此时可以重复读取。否者不能重复消费流。
     */
    public static ContentCachingResponseWrapper getHttpResponseWrapper() {
        ServletRequestAttributes requestAttributes =
            (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        if (requestAttributes == null) {
            log.error("WebUtil 无法获取请求属性");
            return null;
        }
        if (!(requestAttributes.getResponse() instanceof ContentCachingResponseWrapper)) {
            log.error("WebUtil getResponse未包装，不能重复获取，请检查是否配置TraceOncePerRequestFilter");
            return null;
        }
        return (ContentCachingResponseWrapper)requestAttributes.getResponse();
    }

    /**
     * 由于有cn.sixmac.infra.web.filter.TraceOncePerRequestFilter拦截，请求应该是缓存过的，此时可以重复读取。否者不能重复消费流。
     * controller层执行完成之前不会有值，因为还没写进去
     *
     */
    public static @Nullable String getHttpResponseJsonBody() {
        ContentCachingResponseWrapper wrapper = getHttpResponseWrapper();
        if (wrapper == null)
            return null;

        String contentType = wrapper.getContentType();
        if (JSON_TYPES.contains(contentType)) {
            try {
                return new String(wrapper.getContentAsByteArray(), wrapper.getCharacterEncoding());
            } catch (Exception e) {
                log.error("WebUtil HttpServletRequest body流解析失败，返回null", e);
                return null;
            }
        } else {
            log.error("WebUtil HttpServletRequest 格式不支持解析 {}", contentType);
            return null;
        }

    }

}
